CIE: Add conversion from "RGBA float" to "CIE Lab float"
authorDebarshi Ray <debarshir@gnome.org>
Sun, 29 Oct 2017 12:52:26 +0000 (13:52 +0100)
committerØyvind Kolås <pippin@gimp.org>
Tue, 31 Oct 2017 12:08:40 +0000 (13:08 +0100)
Conversions from "RaGaBaA float" to "CIE Lab float", as seen when
using gegl:shadows-highlights" go via:
  "RaGaBaA float" to "RGBA float"
  "RGBA float"    to "RGB float"
  "RGB float"     to "CIE Lab float"

A direct conversion from "RaGaBaA float" to "CIE Lab float" in simple
C is hindered by the need to check every pixel's alpha value to avoid
dividing by zero. The pipeline stalls make it lose out to the look-up
table and SIMD based conversions to unassociated alpha.

However, we can trivially cut out the second step and still reduce
some memory traffic.

https://bugzilla.gnome.org/show_bug.cgi?id=789695

extensions/CIE.c

index d16d86256c3c8a8d8ff920f30e50f726d712d443..a010f0b1ac331e662d0469832c7e9dff660fce9f 100644 (file)
@@ -646,6 +646,40 @@ rgbf_to_Labf (const Babl *conversion,float *src,
     }
 }
 
+static void
+rgbaf_to_Labf (const Babl *conversion,float *src,
+               float *dst,
+               long   samples)
+{
+  long n = samples;
+
+  while (n--)
+    {
+      float r = src[0];
+      float g = src[1];
+      float b = src[2];
+
+      float xr = 0.43603516f / D50_WHITE_REF_X * r + 0.38511658f / D50_WHITE_REF_X * g + 0.14305115f / D50_WHITE_REF_X * b;
+      float yr = 0.22248840f / D50_WHITE_REF_Y * r + 0.71690369f / D50_WHITE_REF_Y * g + 0.06060791f / D50_WHITE_REF_Y * b;
+      float zr = 0.01391602f / D50_WHITE_REF_Z * r + 0.09706116f / D50_WHITE_REF_Z * g + 0.71392822f / D50_WHITE_REF_Z * b;
+
+      float fx = xr > LAB_EPSILON ? _cbrtf (xr) : (LAB_KAPPA * xr + 16.0f) / 116.0f;
+      float fy = yr > LAB_EPSILON ? _cbrtf (yr) : (LAB_KAPPA * yr + 16.0f) / 116.0f;
+      float fz = zr > LAB_EPSILON ? _cbrtf (zr) : (LAB_KAPPA * zr + 16.0f) / 116.0f;
+
+      float L = 116.0f * fy - 16.0f;
+      float A = 500.0f * (fx - fy);
+      float B = 200.0f * (fy - fz);
+
+      dst[0] = L;
+      dst[1] = A;
+      dst[2] = B;
+
+      src += 4;
+      dst += 3;
+    }
+}
+
 static void
 rgbaf_to_Labaf (const Babl *conversion,float *src,
                 float *dst,
@@ -903,6 +937,12 @@ conversions (void)
     "linear", Labf_to_rgbf,
     NULL
   );
+  babl_conversion_new (
+    babl_format ("RGBA float"),
+    babl_format ("CIE Lab float"),
+    "linear", rgbaf_to_Labf,
+    NULL
+  );
   babl_conversion_new (
     babl_format ("RGBA float"),
     babl_format ("CIE Lab alpha float"),